#include "cpu/exec/template-start.h"

#define instr jmp

static void do_execute() {
	if (op_src->type == OP_TYPE_IMM){ //立即数，是偏移量
        cpu.eip += (DATA_TYPE_S)op_src->val;
    }
	else {  //r/m
        int len = concat(decode_rm_, SUFFIX)(cpu.eip + 1);
        cpu.eip = (DATA_TYPE_S)op_src->val - len - 1;
    }
	print_asm_template1();
}

make_instr_helper(i)

#if DATA_BYTE == 2
make_instr_helper(rm)
#endif

#if DATA_BYTE == 4
make_instr_helper(rm)

extern Sreg_Descriptor *sreg_desc;
make_helper(ljmp) { //跳跃到新的段 jmp ptr16:32
	// Log("ljmp: from 0x100000:");
	// Log("0x100000 %x",instr_fetch(0x100000,1));
	// Log("0x100001 %x",instr_fetch(0x100001,1));
	// Log("0x100002 %x",instr_fetch(0x100002,1));
	// Log("0x100003 %x",instr_fetch(0x100003,1));
	// Log("0x100004 %x",instr_fetch(0x100004,1));
	// Log("0x100005 %x",instr_fetch(0x100005,1));
	// Log("0x100006 %x",instr_fetch(0x100006,1));
	// Log("0x100007 %x",instr_fetch(0x100007,1));
	// Log("0x100008 %x",instr_fetch(0x100008,1));
	// Log("0x100009 %x",instr_fetch(0x100009,1));
    // Log("0x10000a %x",instr_fetch(0x10000a,1));
    // Log("0x10000b %x",instr_fetch(0x10000b,1));
    // Log("0x10000c %x",instr_fetch(0x10000c,1));
    // Log("0x10000d %x",instr_fetch(0x10000d,1));
	// Log("0x10000e %x",instr_fetch(0x10000e,1));
    // Log("0x10000f %x",instr_fetch(0x10000f,1));
	// Log("0x100010 %x",instr_fetch(0x100010,1));
	// Log("0x100011 %x",instr_fetch(0x100011,1));
	// Log("0x100012 %x",instr_fetch(0x100012,1));
	// Log("0x100013 %x",instr_fetch(0x100013,1));
	// Log("0x100014 %x",instr_fetch(0x100014,1));
	// Log("0x100015 %x",instr_fetch(0x100015,1));
	// Log("0x100016 %x",instr_fetch(0x100016,1));
	// Log("0x100017 %x",instr_fetch(0x100017,1));



	//Log("eip:%x %x",eip,instr_fetch(eip,1));
	//Log("cpu.eip:%x %x",cpu.eip,instr_fetch(cpu.eip,1));
	//cpu.eip--;
	//eip--;
	//Log("eip:%x %x",eip,instr_fetch(eip,1));
	//Log("cpu.eip:%x %x",cpu.eip,instr_fetch(cpu.eip,1));
	Sreg_Descriptor new_sreg_desc;
	sreg_desc = &new_sreg_desc;
	//32位:偏移量
    uint32_t op1 = instr_fetch(eip + 1,4);
	// Log("op1:0x%x",op1);
	// op1 = instr_fetch(eip + 2,1);
	// Log("op1:0x%x",op1);
	// op1 = instr_fetch(eip + 3,1);
	// Log("op1:0x%x",op1);
	// op1 = instr_fetch(eip + 4,1);
	// Log("op1:0x%x",op1);
	//16位：新位置所使用段的段描述符
    uint16_t op2 = instr_fetch(eip + 1 + 4,2);
	//Log("op2:0x%x",op2);

    cpu.eip = op1 - 7;
	eip = op1 - 7;
    cpu.cs.selector = op2;

	current_sreg = R_CS;
	//最高13位取出索引index
    uint16_t index = cpu.cs.selector >> 3;//INDEX
	//检查索引是否合法：索引*每个条目字节数(8字节)=大小，这个大小应小于段描述符表的最大大小limit
	Assert((index << 3) <= cpu.gdtr.limit,"error:segement selector is Out Of the limit!");
    
	//求出段描述符的线性地址
	lnaddr_t seg_desc_lnaddr = cpu.gdtr.base + (index << 3);
    //printf("seg_desc_lnaddr:0x%x\n",seg_desc_lnaddr);
	//根据线性地址将段描述符读出来，每次最多读32位
	sreg_desc->part1 = lnaddr_read(seg_desc_lnaddr, 4);
	sreg_desc->part2 = lnaddr_read(seg_desc_lnaddr + 4, 4);
	//Log("part1:0x%x",sreg_desc->part1);
	//Log("part2:0x%x",sreg_desc->part2);
	//检查段描述符是否有效
	Assert(sreg_desc->p == 1, "error:segement not exist!");
	
	//取出段的base
    uint32_t base = 0;
	//把拆开的三段base组合成原base
	base += ((uint32_t)sreg_desc->base1);
	base += ((uint32_t)sreg_desc->base2) << 16;
	base += ((uint32_t)sreg_desc->base3) << 24;
	//把base存到CS段寄存器中
    cpu.cs.base = base;

	//取出段的limit
	uint32_t limit = 0;
	limit += ((uint32_t)sreg_desc->limit1);
	limit += ((uint32_t)sreg_desc->limit2) << 16;
	//G位为0的话，Limit高12位就填充0
	//G位为1的话，Limit低12位就填充F
	if (sreg_desc->g == 1) limit = (limit << 12) + (uint32_t)0xfff;
	cpu.cs.limit = limit;


    print_asm("ljmp 0x%x 0x%x",op2,op1);
    return 7; //7是指令字节数
}
#endif
#include "cpu/exec/template-end.h"
